<?php

namespace app\service\api;

use app\model\api\GenshinLevelExperience;
use app\model\api\GenshinRecord;
use app\model\api\GenshinRelics;
use app\model\api\GenshinRole;
use app\model\api\GenshinRoleLevel;
use app\model\api\GenshinSkillLevel;
use app\model\api\GenshinWeapon;
use laytp\traits\Error;
use think\Log;

/**
 * Api原神服务实现者
 * @package app\api\service
 */
class Genshin
{
    use Error;
    /**
     * 当前实例
     * @var object
     */
    protected static $instance;

    /**
     * 抽卡记录结果
     * @var array
     */
    protected $record;

    /**
     * 数据请求url
     * @var string
     */
    protected $baseUrl;

    /**
     * pageSize
     * @var int
     */
    protected $pageSize = 20;

    /**
     * 请求时间间隔 （毫秒）
     * @var int
     */
    protected $interval = 2.5;

    /**
     * 歪角色
     * @var array
     */
    protected $crooked_role = [
        '刻晴',
        '莫娜',
        '七七',
        '迪卢克',
        '琴'
    ];

    /**
     * 歪武器
     * @var array
     */
    protected $crooked_weapon = [
        '阿莫斯之弓',
        '天空之翼',
        '四风原典',
        '天空之卷',
        '和璞鸢',
        '天空之脊',
        '狼的末路',
        '天空之傲',
        '天空之刃',
        '风鹰剑'
    ];

    /**
     * 称号
     * @var array
     */
    protected $title = [
        '0.95' => '欧皇至尊',
        '0.85' => '欧皇大王',
        '0.75' => '欧皇长老',
        '0.65' => '大欧皇',
        '0.55' => '小欧皇',
        '0.45' => '小非酋',
        '0.3'  => '大非酋',
        '0.15' => '非酋长老',
        '0.05' => '非酋大王',
        '0'    => '非酋至尊',
    ];

    /**
     * 每次抽卡消耗
     * @var int
     */
    protected $each_cost = 160;

    /**
     * 获取抽卡记录
     * @param $parseUrl
     * @return array|string
     */
    public function parse($parseUrl){
        $parseUrl = str_replace('&amp;','&',$parseUrl);
        //初始化结果
        $this->record = [];

        $query = parse_url($parseUrl)['query'];
        $queryParts = explode('&', $query);
        $params = array();
        foreach ($queryParts as $param) {
            $item = explode('=', $param);
            $params[$item[0]] = $item[1];
        }

        $params['authkey'] = urldecode($params['authkey']);

        if(isset($params['page'])){unset($params['page']);}
        if(isset($params['size'])){unset($params['size']);}
        if(isset($params['end_id'])){unset($params['end_id']);}
        if(isset($params['gacha_type'])){unset($params['gacha_type']);}
        if(isset($params['ext'])){$params['ext'] = urldecode($params['ext']);}

        if(strpos($parseUrl,'ios') === false){
            $this->baseUrl = 'https://hk4e-api.mihoyo.com/event/gacha_info/api/getGachaLog?'.http_build_query($params).'&gacha_type=%TYPE%&page=%PAGE%&size='.$this->pageSize.'&end_id=%END_ID%';
        }else{
            if(!empty($params['gacha_type'])){unset($params['gacha_type']);}
            $this->baseUrl = 'https://hk4e-api.mihoyo.com/event/gacha_info/api/getGachaLog?'.http_build_query($params).'&gacha_type=%TYPE%&page=%PAGE%&size='.$this->pageSize.'&end_id=%END_ID%';
        }

        try{
            //角色祈愿活动
            self::getContent('301');

            //武器活动祈愿
            self::getContent('302');

            //常驻祈愿
            self::getContent('200');

        }catch (\Exception $e){
            return $e->getMessage();
        }

        //历史数据合并
        (new GenshinRecord())->strict(false)
            ->replace(true)->insertAll($this->record);

        if(empty($this->record)){
            return '无抽卡记录';
        }
        return $this->record[0]['uid'];
    }

    /**
     * 发送请求
     * @param $gacha_type
     * @param int $page
     * @param int $end_id
     * @return array
     * @throws \Exception
     */
    public function getContent($gacha_type,$page = 1,$end_id = 0){
        $url = str_replace('%TYPE%',$gacha_type,$this->baseUrl);
        $url = str_replace('%END_ID%',$end_id,$url);
        $url = str_replace('%PAGE%',$page,$url);

        $result = file_get_contents($url);
        $result = json_decode($result,true);
        $data = [];

        if(!empty($result['data']['list'])){
            $data = $result['data']['list'];
        }else{
            if(isset($result['retcode']) && ($result['retcode'] == -101 || $result['retcode'] == -100)){
                throw new \Exception('链接已失效', 1);
            }
        }
        $scene = 0;
        switch ($gacha_type){
            case '301':
                $scene = 1;
                break;
            case '302':
                $scene = 2;
                break;
            case '200':
                $scene = 3;
                break;
        }

        if(!empty($data)){
            foreach($data as $item){
                $this->record[] = array(
                    'scene' => $scene,
                    'uid' => $item['uid'],
                    'gacha_type' => $item['gacha_type'],
                    'time' => $item['time'],
                    'name' => $item['name'],
                    'item_type' => $item['item_type'],
                    'rank_type' => $item['rank_type'],
                    'record_id' => $item['id'],
                );
            }
        }

        if(count($data) >= $this->pageSize){
            $end_id = $data[$this->pageSize- 1]['id'];

            $page++;
            try{
                usleep($this->interval*100000);
                $this->getContent($gacha_type,$page,$end_id);
            }catch (\Exception $e){
                throw new \Exception($e->getMessage(), 1);
            }
        }
        return $this->record;
    }

    /**
     * 分析
     * @param $list
     * @return array
     */
    public function dataAnalysis($list){
        //角色头像查询
        $role_img = (new GenshinRecord())->getRoleInfo();
        //武器图片查询
        $weapon_img = (new GenshinWeapon())->getWeaponInfo();

        $all_img = array_merge($role_img,$weapon_img);
        /** 角色分析 **/
        //不垫次数
        $no_pad_role_total = 0;
        //五星角色总数
        $all_role = 0;
        //歪角色总数
        $all_crooked_role = 0;
        //角色分析结果
        $role_result = array(array('number' => 0));
        $i = 0;
        foreach($list as $k => $v ){
            if($v['scene'] != 1 ){
                continue;
            }
            $no_pad_role_total++;
            if($v['rank_type'] < 5){
                $role_result[$i]['number'] = !empty($role_result[$i]['number'])?$role_result[$i]['number'] + 1:1;
            }else{
                $i++;
                $all_role++;
                $role_result[$i]['number'] = 1;
                $role_result[$i]['time'] =  date("Y年m月d日",strtotime($v['time']));
                $role_result[$i]['name'] = $v['name'];
                $role_result[$i]['img'] = !empty($all_img[$v['name']]['icon'])?$all_img[$v['name']]['icon']:'';
                $role_result[$i]['is_crooked'] = 0;
                if(in_array($v['name'],$this->crooked_role)){
                    $all_crooked_role++;
                    $role_result[$i]['is_crooked'] = 1;
                }
            }
            unset($list[$k]);
        }

        /** 武器分析 **/
        $no_pad_weapon_total = 0;
        //五星角色总数
        $all_weapon = 0;
        //歪角色总数
        $all_crooked_weapon = 0;
        $weapon_result = array(array('number' => 0));
        $i = 0;
        foreach($list as $k => $v){
            if($v['scene'] != 2 ){
                continue;
            }
            $no_pad_weapon_total++;
            if($v['rank_type'] < 5){
                $weapon_result[$i]['number'] = !empty($weapon_result[$i]['number'])?$weapon_result[$i]['number'] + 1:1;
            }else{
                $i++;
                $all_weapon++;
                $weapon_result[$i]['number'] = 1;
                $weapon_result[$i]['time'] = date("Y年m月d日",strtotime($v['time']));
                $weapon_result[$i]['name'] = $v['name'];
                $weapon_result[$i]['is_crooked'] = 0;
                $weapon_result[$i]['img'] = !empty($all_img[$v['name']]['icon'])?$all_img[$v['name']]['icon']:'';
                if(in_array($v['name'],$this->crooked_weapon)){
                    $all_crooked_weapon++;
                    $weapon_result[$i]['is_crooked'] = 1;
                }
            }
            unset($list[$k]);
        }

        /** 常驻分析 **/
        $no_pad_permanent_total = 0;
        $permanent_result = array(array('number' => 0));
        $i = 0;
        foreach($list as $k => $v){
            if($v['scene'] != 3 ){
                continue;
            }
            $no_pad_permanent_total++;
            if($v['rank_type'] < 5){
                $permanent_result[$i]['number'] = !empty($permanent_result[$i]['number'])?$permanent_result[$i]['number'] + 1:1;
            }else{
                $i++;
                $permanent_result[$i]['number'] = 1;
                $permanent_result[$i]['time'] = date("Y年m月d日",strtotime($v['time']));
                $permanent_result[$i]['name'] = $v['name'];
                $permanent_result[$i]['img'] = !empty($all_img[$v['name']]['icon'])?$all_img[$v['name']]['icon']:'';
                $permanent_result[$i]['type'] = !empty($all_img[$v['name']]['type'])?$all_img[$v['name']]['type']:'';
                $permanent_result[$i]['is_crooked'] = 0;
            }
        }
        $total = array(
            $no_pad_role_total,$no_pad_weapon_total,$no_pad_permanent_total
        );

        /** 小保底不歪概率 **/
        $no_crooked_rate = 0;
        if(!empty($all_role - $all_crooked_role)){
            $no_crooked_rate = sprintf('%.3f',1 - ($all_crooked_role/($all_role - $all_crooked_role)));
        }

        //角色已垫
        $pad_role_number = !empty($role_result[0]['number'])?$role_result[0]['number']:0;
        $no_pad_role_total = $no_pad_role_total - $pad_role_number;
        //武器已垫
        $pad_weapon_number = !empty($weapon_result[0]['number'])?$weapon_result[0]['number']:0;
        $no_pad_weapon_total = $no_pad_weapon_total - $pad_weapon_number;
        //匹配称号
        $role_title_name = '';
        foreach($this->title as $point => $title_name){
            if($no_crooked_rate >= $point){
                $role_title_name = $title_name;
                break;
            }
        }
        //min
        $lucky = $this->getRecentWorkExperience($role_result,'number','min');
        //max
        $no_lucky = $this->getRecentWorkExperience($role_result,'number','max');

        $role_avg = 0;
        $role_avg_cost = 0;
        if(!empty($all_role)){
            $role_avg = sprintf('%.1f',$no_pad_role_total/$all_role);
            if(!empty($all_role - $all_crooked_role)){
                $role_avg_cost = ceil($no_pad_role_total*$this->each_cost/($all_role - $all_crooked_role));
            }
        }
        $weapon_avg = 0;
        $weapon_avg_cost = 0;
        if(!empty($all_weapon)){
            $weapon_avg = sprintf('%.1f',$no_pad_weapon_total/$all_weapon);
            if(!empty($all_weapon - $all_crooked_weapon)){
                $weapon_avg_cost = ceil($no_pad_weapon_total*$this->each_cost/($all_weapon - $all_crooked_weapon));
            }
        }

        return array(
            'no_crooked_rate' => $no_crooked_rate>0?($no_crooked_rate*100).'%':'0%',
            'role_avg'   => $role_avg,
            'weapon_avg' => $weapon_avg,
            'lucky'    => !empty($lucky['name'])?$lucky['name']:"",
            'no_lucky' => !empty($no_lucky['name'])?$no_lucky['name']:"",
            'role_avg_cost'   => $role_avg_cost,
            'weapon_avg_cost' => $weapon_avg_cost,
            'role'   => $role_result,
            'weapon' => $weapon_result,
            'permanent' => $permanent_result,
            'total'     => $total,
            'rank'      => $role_title_name
        );
    }



    /**
     * 二维数组 根据某字段取最大/最小项
     * @param $workExperiences
     * @param $field
     * @param $type
     * @return mixed
     */
    function getRecentWorkExperience($workExperiences,$field,$type)
    {
        krsort($workExperiences);
        foreach($workExperiences as $index => $item){
            if(empty($item['name'])){
                unset($workExperiences[$index]);
            }
        }
        $workExperiences = array_values($workExperiences);
        if(empty($workExperiences)){
            return '';
        }
        foreach($workExperiences as $index => $item){
            if($index > 0 && $workExperiences[ $index - 1 ]['is_crooked'] == 1){
                $workExperiences[$index]['number'] += $workExperiences[ $index - 1]['number'];
            }
        }

        $quitDates  = array_filter(array_column($workExperiences, $field));
        if($type == 'max'){
            //如果只出一个 五星  没歪 或者 次数小于80 运气就不算差
            if(count($workExperiences) == 1 && ($workExperiences[0]['is_crooked'] != 1 || $workExperiences[0]['number'] < 80)){
                return '';
            }
            $ItemKey = array_search(max($quitDates), $quitDates);
            return $workExperiences[$ItemKey];
        }else if($type == 'min'){
            //如果只出一个 五星  歪了 或者 次数大于80 运气就不咋地
            if(count($workExperiences) == 1 && ($workExperiences[0]['is_crooked'] == 1 || $workExperiences[0]['number'] > 80)){
                return '';
            }
            $ItemKey = array_search(min($quitDates), $quitDates);
            return $workExperiences[$ItemKey];
        }
    }


    /**
     * 角色详情
     * @param $role_id
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function roleDetail($role_id){
        $role = (new GenshinRole())->where('id',$role_id)->cache(true)->find()->toArray();

        //面板数据
        $panel = json_decode($role['panel'],true);
        $panel_num = json_decode($role['panel_num'],true);

        //技能
        $skill_level = array(
            $panel['pinga'],
            $panel['ejineng'],
            $panel['qjineng'],
        );
        $skill_icon = [];
        $skill_list = [];
        $skill = json_decode($role['skill'],true);
        foreach($skill as $index => $item){
            $skill_icon[] = $item['icon'];
            $skill_list[] = array(
                'name' => $item['name'],
                'icon' => $item['icon'],
                'level' => $skill_level[$index].'级',
            );
        }

        //推荐武器
        $weapon_info = (new GenshinWeapon())->getWeaponInfo();
        $recommend_weapon = json_decode($role['recommend_weapon'],true);
        foreach($recommend_weapon as $index => $item){
            $recommend_weapon[$index]['stars'] = $item['rarity'];
            $recommend_weapon[$index]['icon'] = $weapon_info[$item['name']]['icon'];
        }
        //推荐圣遗物
        $relics_info = (new GenshinRelics())->getRelicsInfo();
        $recommend_relics = json_decode($role['recommend_relics'],true);
        foreach($recommend_relics as $indexs => $items){
            foreach($items as $index => $item){
                $recommend_relics[$indexs][$index]['name'] = $item['set_name'];
                $recommend_relics[$indexs][$index]['icon'] = $relics_info[$item['set_name']]['icon'];
                $recommend_relics[$indexs][$index]['count'] = $item['num'];
                $recommend_relics[$indexs][$index]['stars'] = $relics_info[$item['set_name']]['star'];
                unset($recommend_relics[$indexs][$index]['set_name']);
                unset($recommend_relics[$indexs][$index]['img']);
                unset($recommend_relics[$indexs][$index]['num']);
            }
        }

        $team_info = json_decode($role['recommend_team'],true);
        $role_info = (new GenshinRole())->roleInfo();

        foreach($team_info as $index => $item){
            foreach($item['teamlist'] as $team_index => $team){
                $team_info[$index]['teamlist'][$team_index]['avatar'] = $role_info[$team['id']]['head_img'];
            }
        }

        //主词条
        $main_entry_list = [];
        $main_entry = json_decode($role['main_entry'],true);
        foreach($main_entry as $item){
            $main_entry_list[] = $item[0];
        }

        $add_point = array_reverse(json_decode($role['add_point_recommed'],true));
        $return = array(
            'id' => $role['id'],
            'name' => $role['role_name'],
            'position' => explode('/',$role['position']),
            'stars' => $role['star'],
            'element' => $role['element'],
            'radar' => json_decode($role['wuwei'],true),
            'stand' => $role['stand'],
            'nation' => $role['nation'],
            'baseinfo' => array(
                'title' => $role['title'],
                'birthday' => $role['birthday'],
                'nation' => $role['suoshu'],
                'alias' => $role['alias'],
                'tag' => explode(',',$role['tag']),
                'constellation' => $role['mingzuo'],
                'weapon' => $role['weapon'],
                'breakthrough' => $role['breach'],
                'intro' => $role['introduce'],
                'comment' => $role['comment'],
            ),
            'playinfo' => array(
                'position' => json_decode($role['wanfa'],true),
                'weapon' => $recommend_weapon,
                'artifact' => $recommend_relics,
                'mainstats' => $main_entry_list,
                'substats' => json_decode($role['sub_entry'],true),
                'add_point' => $add_point,
                'skill' => self::addPointSkill($skill_icon,$add_point),
                'constellation' => json_decode($role['core_mingzuo'],true),
            ),
            'teaminfo' => $team_info,
            'graduation' => array(
                'attribute' => self::panelData($panel,$panel_num),
                'talent' => $skill_list
            ),


        );
        return $return;

    }

    /**
     * 面板数据
     * @param $panel
     * @param $panel_num
     */
    public function panelData($panel,$panel_num){
        $attribute = array(
            'health'=> array(
                'value' => $panel['shengming'],
                'percent' => $panel_num['health']
            ),
            'attack'=> array(
                'value' => $panel['gongji'],
                'percent' => $panel_num['attack']
            ),
            'defense'=> array(
                'value' => $panel['fangyu'],
                'percent' => $panel_num['defense']
            ),
            'crit'=> array(
                'value' => $panel['baoji'],
                'percent' => $panel_num['crit']
            ),
            'critDamage'=> array(
                'value' => $panel['baoshang'],
                'percent' => $panel_num['critDamage']
            ),
            'elementMastery'=> array(
                'value' => $panel['yuansujingtong'],
                'percent' => $panel_num['elementMastery']
            ),
            'elementCharge'=> array(
                'value' => $panel['yuansuchongneng'],
                'percent' => $panel_num['elementCharge']
            ),
            'elementBonus'=> array(
                'value' => $panel['yuansujiacheng'],
                'percent' => $panel_num['elementBonus']
            ),
        );

        return $attribute;
    }

    /**
     * 技能加点推荐
     * @param $skill_icon
     * @param $add_point
     * @return array
     */
    public function addPointSkill($skill_icon,$add_point){
        $return = [];
        foreach($add_point as $pos){
            switch($pos){
                case 'Q':
                    $return[] = $skill_icon[2];
                    break;
                case 'E':
                    $return[] = $skill_icon[1];
                    break;
                case 'A':
                    $return[] = $skill_icon[0];
                    break;
            }
        }
        return $return;
    }


    /**
     * 角色升级
     * @param $role_id
     * @param $start_level
     * @param $target_level
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function roleLevel($role_id,$start_level,$target_level){
        $material_list = (new GenshinRoleLevel())->where('role_id',$role_id)
            ->where('level','>=',$start_level)
            ->where('level','<',$target_level)->select()->toArray();

        $material= array();
        foreach($material_list as $value){
            $level_material = json_decode($value['material'],true);
            foreach($level_material as $item){
                if(!empty($item['name']) && !empty($item['num'])){
                    if(!empty($material[$item['name']])){
                        $material[$item['name']]['count'] += $item['num'];
                    }else{
                        $material[$item['name']] = array(
                            'name' => $item['name'],
                            'icon' => $item['icon'],
                            'count' => $item['num']
                        );
                    }
                }
            }
        }

        $experience = (new GenshinLevelExperience())
            ->where(function($query) use ($start_level,$target_level){
                $query->where('level','<',$target_level)->where('level','>=',$start_level);
            })
            ->sum('experience');

        $experience_num = ceil($experience/20000);
        if($experience_num > 0){
            $material['大英雄的经验']['count'] = $experience_num;
        }

        $material = array_values($material);
        return $material;
    }


    /**
     * 技能升级材料
     * @param $role_id
     * @param $skill_level
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function skillLevel($role_id,$skill_level){
        $material_list = (new GenshinSkillLevel())->where(['role_id'=>$role_id])->cache(true)
            ->select()->toArray();

        $material= array();
        foreach($material_list as $value){
            if(empty($skill_level[$value['skill_id']])){
                continue;
            }
            if($skill_level[$value['skill_id']]['start_level'] > $value['level']){
                continue;
            }
            if($skill_level[$value['skill_id']]['end_level'] - 1 < $value['level']){
                continue;
            }

            $level_material = json_decode($value['material'],true);
            foreach($level_material['avatar_skill_consume'] as $item){
                if(!empty($item['name']) && !empty($item['num'])){
                    if(!empty($material[$item['name']])){
                        $material[$item['name']]['count'] += $item['num'];
                    }else{
                        $material[$item['name']] = array(
                            'name' => $item['name'],
                            'icon' => $item['icon'],
                            'count' => $item['num']
                        );
                    }
                }
            }
        }
        return array_values($material);
    }
}